
#include "stm32g0xx_ll_flash.h"

#ifdef USE_FULL_ASSERT
#include "stm32_assert.h"
#else
#define assert_param(expr) ((void)0U)
#endif /* USE_FULL_ASSERT */

static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data);
static __RAM_FUNC void FLASH_Program_Fast(uint32_t Address, uint32_t DataAddress);
/**
 * @brief  Program double word or fast program of a row at a specified address.
 * @param  TypeProgram Indicate the way to program at a specified address.
 *                      This parameter can be a value of @ref FLASH_Type_Program
 * @param  Address Specifies the address to be programmed.
 * @param  Data Specifies the data to be programmed
 *               This parameter is the data for the double word program and the address where
 *               are stored the data for the row fast program depending on the TypeProgram:
 *               TypeProgram = FLASH_TYPEPROGRAM_DOUBLEWORD (64-bit)
 *               TypeProgram = FLASH_TYPEPROGRAM_FAST (32-bit).
 *
 * @retval LL_StatusTypeDef LL Status
 */
ErrorStatus LL_FLASH_Program(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
    ErrorStatus status;

    /* Check the parameters */
    assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

    if (status == SUCCESS)
    {
        if (TypeProgram == FLASH_TYPEPROGRAM_DOUBLEWORD)
        {
            /* Check the parameters */
            assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));

            /* Program double-word (64-bit) at a specified address */
            FLASH_Program_DoubleWord(Address, Data);
        }
        else
        {
            /* Check the parameters */
            assert_param(IS_FLASH_FAST_PROGRAM_ADDRESS(Address));

            /* Fast program a 32 row double-word (64-bit) at a specified address */
            FLASH_Program_Fast(Address, (uint32_t)Data);
        }

        /* Wait for last operation to be completed */
        status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

        /* If the program operation is completed, disable the PG or FSTPG Bit */
        CLEAR_BIT(FLASH->CR, TypeProgram);
    }
    /* return status */
    return status;
}

/**
 * @brief  Program double word or fast program of a row at a specified address with interrupt enabled.
 * @param  TypeProgram Indicate the way to program at a specified address.
 *                      This parameter can be a value of @ref FLASH_Type_Program
 * @param  Address Specifies the address to be programmed.
 * @param  Data Specifies the data to be programmed
 *               This parameter is the data for the double word program and the address where
 *               are stored the data for the row fast program depending on the TypeProgram:
 *               TypeProgram = FLASH_TYPEPROGRAM_DOUBLEWORD (64-bit)
 *               TypeProgram = FLASH_TYPEPROGRAM_FAST (32-bit).
 *
 * @retval LL Status
 */
ErrorStatus LL_FLASH_Program_IT(uint32_t TypeProgram, uint32_t Address, uint64_t Data)
{
    ErrorStatus status;

    /* Check the parameters */
    assert_param(IS_FLASH_TYPEPROGRAM(TypeProgram));

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

    if (status != SUCCESS)
    {
    }
    else
    {

        /* Enable End of Operation and Error interrupts */
        FLASH->CR |= FLASH_CR_EOPIE | FLASH_CR_ERRIE;

        if (TypeProgram == FLASH_TYPEPROGRAM_DOUBLEWORD)
        {
            /* Check the parameters */
            assert_param(IS_FLASH_PROGRAM_ADDRESS(Address));

            /* Program double-word (64-bit) at a specified address */
            FLASH_Program_DoubleWord(Address, Data);
        }
        else
        {
            /* Check the parameters */
            assert_param(IS_FLASH_FAST_PROGRAM_ADDRESS(Address));

            /* Fast program a 32 row double-word (64-bit) at a specified address */
            FLASH_Program_Fast(Address, (uint32_t)Data);
        }
    }
    /* return status */
    return status;
}

/**
 * @brief  Mass erase of FLASH memory.
 * @param  Banks: Banks to be erased
 *         This parameter can be a combination of the following values:
 *            @arg FLASH_BANK_1: Bank1 to be erased
 *            @arg FLASH_BANK_2: Bank2 to be erased*
 * @note (*) availability depends on devices
 * @retval None
 */
static void FLASH_MassErase(uint32_t Banks)
{
    /* Check the parameters */
    assert_param(IS_FLASH_BANK(Banks));

    /* Set the Mass Erase Bit and start bit */
    FLASH->CR |= (FLASH_CR_STRT | Banks);
}
/**
 * @brief  Erase the specified FLASH memory page.
 * @param  Banks: Banks to be erased
 *         This parameter can one of the following values:
 *            @arg FLASH_BANK_1: Bank1 to be erased
 *            @arg FLASH_BANK_2: Bank2 to be erased*
 * @param  Page FLASH page to erase
 *         This parameter must be a value between 0 and (max number of pages in Flash - 1)
 * @note (*) availability depends on devices
 * @retval None
 */
void FLASH_PageErase(uint32_t Banks, uint32_t Page)
{
    uint32_t tmp;

    /* Check the parameters */
    assert_param(IS_FLASH_BANK(Banks));
    assert_param(IS_FLASH_PAGE(Page));

    /* Get configuration register, then clear page number */
    tmp = (FLASH->CR & ~FLASH_CR_PNB);

#if defined(FLASH_DBANK_SUPPORT)
    /* Check if page has to be erased in bank 1 or 2 */
    if (Banks != FLASH_BANK_1)
    {
        tmp |= FLASH_CR_BKER;
    }
    else
    {
        tmp &= ~FLASH_CR_BKER;
    }
#endif /* FLASH_DBANK_SUPPORT */

    /* Set page number, Page Erase bit & Start bit */
    FLASH->CR = (tmp | (FLASH_CR_STRT | (Page << FLASH_CR_PNB_Pos) | FLASH_CR_PER));
}

/**
 * @brief  Perform a mass erase or erase the specified FLASH memory pages.
 * @param[in]  pEraseInit Pointer to an @ref FLASH_EraseInitTypeDef structure that
 *         contains the configuration information for the erasing.
 * @param[out]  PageError Pointer to variable that contains the configuration
 *         information on faulty page in case of error (0xFFFFFFFF means that all
 *         the pages have been correctly erased)
 * @retval LL Status
 */
ErrorStatus LL_FLASHEx_Erase(FLASH_EraseInitTypeDef *pEraseInit, uint32_t *PageError)
{
    ErrorStatus status;
    uint32_t index;

    /* Check the parameters */
    assert_param(IS_FLASH_TYPEERASE(pEraseInit->TypeErase));

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

    if (status == SUCCESS)
    {
#if !defined(FLASH_DBANK_SUPPORT)
        /* For single bank product force Banks to Bank 1 */
        pEraseInit->Banks = FLASH_BANK_1;
#endif /* FLASH_DBANK_SUPPORT */

        if (pEraseInit->TypeErase == FLASH_TYPEERASE_MASS)
        {
            /* Proceed to Mass Erase */
            FLASH_MassErase(pEraseInit->Banks);

            /* Wait for last operation to be completed */
            status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);
        }
        else
        {
            /*Initialization of PageError variable*/
            *PageError = 0xFFFFFFFFU;

            for (index = pEraseInit->Page; index < (pEraseInit->Page + pEraseInit->NbPages); index++)
            {
                /* Start erase page */
                FLASH_PageErase(pEraseInit->Banks, index);

                /* Wait for last operation to be completed */
                status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

                if (status != SUCCESS)
                {
                    /* In case of error, stop erase procedure and return the faulty address */
                    *PageError = index;
                    break;
                }
            }

            /* If operation is completed or interrupted, disable the Page Erase Bit */
            CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
        }
    }
    /* return status */
    return status;
}
/**
 * @brief  Unlock the FLASH control register access.
 * @retval LL Status
 */
ErrorStatus LL_Flash_Unlock(void)
{
    ErrorStatus status = SUCCESS;
    if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
    {
        /* Authorize the FLASH Registers access */
        WRITE_REG(FLASH->KEYR, FLASH_KEY1);
        WRITE_REG(FLASH->KEYR, FLASH_KEY2);

        /* verify Flash is unlock */
        if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00U)
        {
            status = ERROR;
        }
    }
    return status; // Done
}

/**
 * @brief  Lock the FLASH control register access.
 * @retval LL Status
 */
ErrorStatus LL_Flash_lock(void)
{
    ErrorStatus status = ERROR;
    SET_BIT(FLASH->CR, FLASH_CR_LOCK);

    if (READ_BIT(FLASH->CR, FLASH_CR_LOCK) != 0x00u)
    {
        status = SUCCESS;
    }
    return status; // Done
}

/**
 * @brief  Unlock the FLASH Option Bytes Registers access.
 * @retval LL Status
 */
ErrorStatus LL_Flash_OB_lock(void)
{
    ErrorStatus status = ERROR;
    if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00U)
    {
        /* Authorizes the Option Byte register programming */
        WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY1);
        WRITE_REG(FLASH->OPTKEYR, FLASH_OPTKEY2);

        /* verify option bytes are unlocked */
        if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) == 0x00U)
        {
            status = SUCCESS;
        }
    }

    return status; // Done
}

/**
 * @brief  Unlock the FLASH Option Bytes Registers access.
 * @retval LL Status
 */
ErrorStatus LL_Flash_OB_Unlock(void)
{
    ErrorStatus status = ERROR;

    /* Set the OPTLOCK Bit to lock the FLASH Option Byte Registers access */
    SET_BIT(FLASH->CR, FLASH_CR_OPTLOCK);

    /* verify option bytes are locked */
    if (READ_BIT(FLASH->CR, FLASH_CR_OPTLOCK) != 0x00u)
    {
        status = SUCCESS;
    }

    return status;
}

/**
 * @brief  Launch the option byte loading.
 * @retval LL Status
 */
ErrorStatus LL_FLASH_OB_Launch(void)
{
    /* Set the bit to force the option byte reloading */
    SET_BIT(FLASH->CR, FLASH_CR_OBL_LAUNCH);

    /* We should not reach here : Option byte launch generates Option byte reset
       so return error */
    return ERROR;
}

/**
 * @brief  Wait for a FLASH operation to complete.
 * @param  Timeout maximum flash operation timeout
 * @retval LL_StatusTypeDef LL Status
 */
ErrorStatus FLASH_WaitForLastOperation(uint32_t Timeout)
{
    uint32_t error;
#if defined(FLASH_DBANK_SUPPORT)
    error = (FLASH_SR_BSY1 | FLASH_SR_BSY2);
#else
    error = FLASH_SR_BSY1;
#endif /* FLASH_DBANK_SUPPORT */
    uint32_t timeout = Timeout;
    while ((FLASH->SR & error) != 0x00U)
    {
        timeout--;
        if (timeout == 0)
        {
            return ERROR;
        }
    }

    /* check flash errors */
    error = (FLASH->SR & FLASH_SR_ERRORS);

    /* Clear SR register */
    FLASH->SR = FLASH_SR_CLEAR;

    if (error != 0x00U)
    {
        return ERROR;
    }
    timeout = Timeout;
    while ((FLASH->SR & FLASH_SR_CFGBSY) != 0x00U)
    {
        timeout--;
        if (timeout == 0)
        {
            return ERROR;
        }
    }

    return SUCCESS;
}

/**
 * @brief  Program double-word (64-bit) at a specified address.
 * @param  Address Specifies the address to be programmed.
 * @param  Data Specifies the data to be programmed.
 * @retval None
 */
static void FLASH_Program_DoubleWord(uint32_t Address, uint64_t Data)
{
    /* Set PG bit */
    SET_BIT(FLASH->CR, FLASH_CR_PG);

    /* Program first word */
    *(uint32_t *)Address = (uint32_t)Data;

    /* Barrier to ensure programming is performed in 2 steps, in right order
      (independently of compiler optimization behavior) */
    __ISB();

    /* Program second word */
    *(uint32_t *)(Address + 4U) = (uint32_t)(Data >> 32U);
}

/**
 * @brief  Fast program a 32 row double-word (64-bit) at a specified address.
 * @param  Address Specifies the address to be programmed.
 * @param  DataAddress Specifies the address where the data are stored.
 * @retval None
 */
static __RAM_FUNC void FLASH_Program_Fast(uint32_t Address, uint32_t DataAddress)
{
    uint8_t index = 0;
    uint32_t dest = Address;
    uint32_t src = DataAddress;
    uint32_t primask_bit;

    /* Set FSTPG bit */
    SET_BIT(FLASH->CR, FLASH_CR_FSTPG);

    /* Enter critical section: row programming should not be longer than 7 ms */
    primask_bit = __get_PRIMASK();
    __disable_irq();

    /* Fast Program : 64 words */
    while (index < 64U)
    {
        *(uint32_t *)dest = *(uint32_t *)src;
        src += 4U;
        dest += 4U;
        index++;
    }

    /* wait for BSY1 in order to be sure that flash operation is ended befoire
       allowing prefetch in flash. Timeout does not return status, as it will
       be anyway done later */

#if defined(FLASH_DBANK_SUPPORT)
    while ((FLASH->SR & (FLASH_SR_BSY1 | FLASH_SR_BSY2)) != 0x00U)
#else
    while ((FLASH->SR & FLASH_SR_BSY1) != 0x00U)
#endif /* FLASH_DBANK_SUPPORT */
    {
    }

    /* Exit critical section: restore previous priority mask */
    __set_PRIMASK(primask_bit);
}



///OB



/**
  * @brief  Set user & RDP configuration
  * @note   !!! Warning : When enabling OB_RDP level 2 it is no more possible
  *         to go back to level 1 or 0 !!!
  * @param  UserType  The FLASH User Option Bytes to be modified.
  *         This parameter can be a combination of @ref FLASH_OB_USER_Type
  * @param  UserConfig  The FLASH User Option Bytes values.
  *         This parameter can be a combination of:
  *           @arg @ref FLASH_OB_USER_BOR_ENABLE(*)
  *           @arg @ref FLASH_OB_USER_BOR_LEVEL(*)
  *           @arg @ref FLASH_OB_USER_RESET_CONFIG(*)
  *           @arg @ref FLASH_OB_USER_nRST_STOP
  *           @arg @ref FLASH_OB_USER_nRST_STANDBY
  *           @arg @ref FLASH_OB_USER_nRST_SHUTDOWN(*)
  *           @arg @ref FLASH_OB_USER_IWDG_SW
  *           @arg @ref FLASH_OB_USER_IWDG_STOP
  *           @arg @ref FLASH_OB_USER_IWDG_STANDBY
  *           @arg @ref FLASH_OB_USER_WWDG_SW
  *           @arg @ref FLASH_OB_USER_SRAM_PARITY
  *           @arg @ref FLASH_OB_USER_BANK_SWAP(*)
  *           @arg @ref FLASH_OB_USER_DUAL_BANK(*)
  *           @arg @ref FLASH_OB_USER_nBOOT_SEL
  *           @arg @ref FLASH_OB_USER_nBOOT1
  *           @arg @ref FLASH_OB_USER_nBOOT0
  *           @arg @ref FLASH_OB_USER_INPUT_RESET_HOLDER(*)
  * @param  RDPLevel  specifies the read protection level.
  *         This parameter can be one of the following values:
  *           @arg @ref OB_RDP_LEVEL_0 No protection
  *           @arg @ref OB_RDP_LEVEL_1 Memory Read protection
  *           @arg @ref OB_RDP_LEVEL_2 Full chip protection
  * @note  (*) availability depends on devices
  * @retval None
  */
static void FLASH_OB_OptrConfig(uint32_t UserType, uint32_t UserConfig, uint32_t RDPLevel)
{
  uint32_t optr;

  /* Check the parameters */
  assert_param(IS_OB_USER_TYPE(UserType));
  assert_param(IS_OB_USER_CONFIG(UserType, UserConfig));
  assert_param(IS_OB_RDP_LEVEL(RDPLevel));

  /* Configure the RDP level in the option bytes register */
  optr = FLASH->OPTR;
  optr &= ~(UserType | FLASH_OPTR_RDP);
  FLASH->OPTR = (optr | UserConfig | RDPLevel);
}

/**
  * @brief  Return the FLASH Read Protection level.
  * @retval FLASH ReadOut Protection Status:
  *         This return value can be one of the following values:
  *           @arg @ref OB_RDP_LEVEL_0 No protection
  *           @arg @ref OB_RDP_LEVEL_1 Read protection of the memory
  *           @arg @ref OB_RDP_LEVEL_2 Full chip protection
  */
static uint32_t FLASH_OB_GetRDP(void)
{
  uint32_t rdplvl = READ_BIT(FLASH->OPTR, FLASH_OPTR_RDP);

  if ((rdplvl != OB_RDP_LEVEL_0) && (rdplvl != OB_RDP_LEVEL_2))
  {
    return (OB_RDP_LEVEL_1);
  }
  else
  {
    return rdplvl;
  }
}

/**
  * @brief  Return the FLASH User Option Byte value.
  * @retval The FLASH User Option Bytes values. It will be a combination of all the following values:
  *           @arg @ref FLASH_OB_USER_BOR_ENABLE(*)
  *           @arg @ref FLASH_OB_USER_BOR_LEVEL(*)
  *           @arg @ref FLASH_OB_USER_RESET_CONFIG(*)
  *           @arg @ref FLASH_OB_USER_nRST_STOP
  *           @arg @ref FLASH_OB_USER_nRST_STANDBY
  *           @arg @ref FLASH_OB_USER_nRST_SHUTDOWN(*)
  *           @arg @ref FLASH_OB_USER_IWDG_SW
  *           @arg @ref FLASH_OB_USER_IWDG_STOP
  *           @arg @ref FLASH_OB_USER_IWDG_STANDBY
  *           @arg @ref FLASH_OB_USER_WWDG_SW
  *           @arg @ref FLASH_OB_USER_SRAM_PARITY
  *           @arg @ref FLASH_OB_USER_BANK_SWAP(*)
  *           @arg @ref FLASH_OB_USER_DUAL_BANK(*)
  *           @arg @ref FLASH_OB_USER_nBOOT_SEL
  *           @arg @ref FLASH_OB_USER_nBOOT1
  *           @arg @ref FLASH_OB_USER_nBOOT0
  *           @arg @ref FLASH_OB_USER_INPUT_RESET_HOLDER(*)
  * @note  (*) availability depends on devices
  */
static uint32_t FLASH_OB_GetUser(void)
{
  uint32_t user = ((FLASH->OPTR & ~FLASH_OPTR_RDP) & OB_USER_ALL);
  return user;
}



/**
  * @brief  Configure the write protection of the desired pages.
  * @note   When WRP is active in a zone, it cannot be erased or programmed.
  *         Consequently, a software mass erase cannot be performed if one zone
  *         is write-protected.
  * @note   When the memory read protection level is selected (RDP level = 1),
  *         it is not possible to program or erase Flash memory if the CPU debug
  *         features are connected (JTAG or single wire) or boot code is being
  *         executed from RAM or System flash, even if WRP is not activated.
  * @param  WRPArea  Specifies the area to be configured.
  *         This parameter can be one of the following values:
  *           @arg @ref OB_WRPAREA_ZONE_A Flash Zone A
  *           @arg @ref OB_WRPAREA_ZONE_B Flash Zone B
  *           @arg @ref OB_WRPAREA_ZONE2_A Flash Bank 2 Zone A (*)
  *           @arg @ref OB_WRPAREA_ZONE2_B Flash Bank 2 Zone B (*)
  * @note  (*) availability depends on devices
  * @param  WRPStartOffset  Specifies the start page of the write protected area
  *         This parameter can be page number between 0 and (max number of pages in the Flash Bank - 1)
  * @param  WRDPEndOffset  Specifies the end page of the write protected area
  *         This parameter can be page number between WRPStartOffset and (max number of pages in the Flash Bank - 1)
  * @retval None
  */
static void FLASH_OB_WRPConfig(uint32_t WRPArea, uint32_t WRPStartOffset, uint32_t WRDPEndOffset)
{
  /* Check the parameters */
  assert_param(IS_OB_WRPAREA(WRPArea));
  assert_param(IS_FLASH_PAGE(WRPStartOffset));
  assert_param(IS_FLASH_PAGE(WRDPEndOffset));

  /* Configure the write protected area */
  if (WRPArea == OB_WRPAREA_ZONE_A)
  {
    FLASH->WRP1AR = ((WRDPEndOffset << FLASH_WRP1AR_WRP1A_END_Pos) | WRPStartOffset);
  }
  else
  {
    FLASH->WRP1BR = ((WRDPEndOffset << FLASH_WRP1BR_WRP1B_END_Pos) | WRPStartOffset);
  }
}

/**
  * @brief  Program Option bytes.
  * @param  pOBInit Pointer to an @ref FLASH_OBProgramInitTypeDef structure that
  *         contains the configuration information for the programming.
  * @note   To configure any option bytes, the option lock bit OPTLOCK must be
  *         cleared with the call of @ref LL_FLASH_OB_Unlock() function.
  * @note   New option bytes configuration will be taken into account only
  *         - after an option bytes launch through the call of @ref LL_FLASH_OB_Launch()
  *         - a Power On Reset
  *         - an exit from Standby or Shutdown mode.
  * @retval LL Status
  */
ErrorStatus LL_FLASHEx_OBProgram(FLASH_OBProgramInitTypeDef *pOBInit)
{
  uint32_t optr;
  ErrorStatus status;

  /* Check the parameters */
  assert_param(IS_OPTIONBYTE(pOBInit->OptionType));

  /* Write protection configuration */
  if ((pOBInit->OptionType & OPTIONBYTE_WRP) != 0x00U) 
  {
    /* Configure of Write protection on the selected area */
    FLASH_OB_WRPConfig(pOBInit->WRPArea, pOBInit->WRPStartOffset, pOBInit->WRPEndOffset);
  }

  /* Option register */
  if ((pOBInit->OptionType & (OPTIONBYTE_RDP | OPTIONBYTE_USER)) == (OPTIONBYTE_RDP | OPTIONBYTE_USER))
  {
    /* Fully modify OPTR register with RDP & user data */
    FLASH_OB_OptrConfig(pOBInit->USERType, pOBInit->USERConfig, pOBInit->RDPLevel);
  }
  else if ((pOBInit->OptionType & OPTIONBYTE_RDP) != 0x00U)
  {
    /* Only modify RDP so get current user data */
    optr = FLASH_OB_GetUser();
    FLASH_OB_OptrConfig(optr, optr, pOBInit->RDPLevel);
  }
  else if ((pOBInit->OptionType & OPTIONBYTE_USER) != 0x00U)
  {
    /* Only modify user so get current RDP level */
    optr = FLASH_OB_GetRDP();
    FLASH_OB_OptrConfig(pOBInit->USERType, pOBInit->USERConfig, optr);
  }
  else
  {
    /* nothing to do */
  }

  /* Wait for last operation to be completed */
  status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

  if (status == SUCCESS)
  {
    /* Set OPTSTRT Bit */
    SET_BIT(FLASH->CR, FLASH_CR_OPTSTRT);

    /* Wait for last operation to be completed */
    status = FLASH_WaitForLastOperation(FLASH_TIMEOUT_VALUE);

    /* If the option byte program operation is completed, disable the OPTSTRT Bit */
    CLEAR_BIT(FLASH->CR, FLASH_CR_OPTSTRT);
  }

  /* return status */
  return status;
}

/**
  * @brief  Return the FLASH Write Protection Option Bytes value.
  * @param[in]  WRPArea Specifies the area to be returned.
  *             This parameter can be one of the following values:
  *               @arg @ref OB_WRPAREA_ZONE_A Flash Zone A
  *               @arg @ref OB_WRPAREA_ZONE_B Flash Zone B
  *               @arg @ref OB_WRPAREA_ZONE2_A Flash Bank 2 Zone A (*)
  *               @arg @ref OB_WRPAREA_ZONE2_B Flash Bank 2 Zone B (*)
  * @note  (*) availability depends on devices
  * @param[out]  WRPStartOffset  Specifies the address where to copied the start page
  *                         of the write protected area
  * @param[out]  WRDPEndOffset  Dpecifies the address where to copied the end page of
  *                        the write protected area
  * @retval None
  */
static void FLASH_OB_GetWRP(uint32_t WRPArea, uint32_t *WRPStartOffset, uint32_t *WRDPEndOffset)
{
  /* Check the parameters */
  assert_param(IS_OB_WRPAREA(WRPArea));

  /* Get the configuration of the write protected area */
  if (WRPArea == OB_WRPAREA_ZONE_A)
  {
    *WRPStartOffset = READ_BIT(FLASH->WRP1AR, FLASH_WRP1AR_WRP1A_STRT);
    *WRDPEndOffset = (READ_BIT(FLASH->WRP1AR, FLASH_WRP1AR_WRP1A_END) >> FLASH_WRP1AR_WRP1A_END_Pos);
  }
  else
  {
    *WRPStartOffset = READ_BIT(FLASH->WRP1BR, FLASH_WRP1BR_WRP1B_STRT);
    *WRDPEndOffset = (READ_BIT(FLASH->WRP1BR, FLASH_WRP1BR_WRP1B_END) >> FLASH_WRP1BR_WRP1B_END_Pos);
  }
}

/**
  * @brief  Get the Option bytes configuration.
  * @note   warning: this API only read flash register, it does not reflect any
  *         change that would have been programmed between previous Option byte
  *         loading and current call.
  * @param  pOBInit Pointer to an @ref FLASH_OBProgramInitTypeDef structure that contains the
  *                  configuration information. The fields pOBInit->WRPArea should
  *                  indicate which area is requested for the WRP.
  * @retval None
  */
void LL_FLASHEx_OBGetConfig(FLASH_OBProgramInitTypeDef *pOBInit)
{
  pOBInit->OptionType = OPTIONBYTE_ALL;

  /* Get write protection on the selected area */
  FLASH_OB_GetWRP(pOBInit->WRPArea, &(pOBInit->WRPStartOffset), &(pOBInit->WRPEndOffset));

  /* Get Read protection level */
  pOBInit->RDPLevel = FLASH_OB_GetRDP();

  /* Get the user option bytes */
  pOBInit->USERConfig = FLASH_OB_GetUser();
  pOBInit->USERType = OB_USER_ALL;

}





